import CodingType from './CodingType.js';
import CodingClassKind from './CodingClassKind.js';

export default class CodingClass extends CodingType {

    imports = new Set();
    caption = '';
    lombok = false;
    /**
     * @type {[String]}
     */
    annotations = [];
    modifier = '';
    kind = CodingClassKind.CLASS;
    /**
     * 继承的类型清单，接口继承时可能有多个
     * @type [{CodingType}]
     */
    extends = [];
    /**
     * @type {[CodingType]}
     */
    implements = [];
    /**
     * @type {[CodingProperty]}
     */
    properties = [];
    /**
     * @type {[CodingMethod]}
     */
    methods = [];
    /**
     * @type {CodingClass}
     */
    inner = null;

    addImportClass(...importClasses) {
        for (let importClass of importClasses) {
            if (importClass) {
                if (typeof importClass === 'string') {
                    importClass = new CodingType(importClass);
                }
                if (importClass.packageName && importClass.packageName !== 'java.lang'
                    && importClass.packageName !== this.packageName) {
                    this.imports.add(importClass.getName());
                }
                if (importClass instanceof CodingType) {
                    for (let genericType of importClass.genericTypes) {
                        this.addImportClass(genericType);
                    }
                }
            }
        }
    }

    toString(onlyMain = false) {
        let s = '';
        if (!onlyMain) {
            if (this.packageName) {
                s += `package ${this.packageName};\n\n`;
            }
            if (this.caption || this.properties.some(p => p.caption)) {
                this.imports.add('org.truenewx.tnxjee.core.caption.Caption');
            }
            if (this.lombok) {
                this.imports.add('lombok.Getter');
                this.imports.add('lombok.Setter');
            }
            this.addImportClass(...this.extends);
            this.addImportClass(...this.implements);
            for (let genericType of this.genericTypes) {
                this.addImportClass(genericType);
            }

            if (this.inner) { // 将内部类中需要导入的类放在主类中导入
                this.inner.imports.forEach(importClassName => this.imports.add(importClassName));
                this.addImportClass(...this.inner.extends);
                this.addImportClass(...this.inner.implements);
            }

            for (let property of this.properties) {
                this.addImportClass(property.type);
            }

            for (let method of this.methods) {
                this.addImportClass(method.returnType);
                for (let parameter of method.parameters) {
                    this.addImportClass(parameter.type);
                }
            }

            let importClassNames = [...this.imports].sort((a, b) => a.localeCompare(b));
            for (let importClassName of importClassNames) {
                s += `import ${importClassName};\n`;
            }
            if (this.imports.size) {
                s += '\n';
            }
        }
        if (this.caption) {
            s += `@Caption("${this.caption}")\n`;
        }
        if (this.lombok) {
            s += '@Getter\n@Setter\n';
        }
        for (let annotation of this.annotations) {
            s += `@${annotation}\n`;
        }
        let modifier = this.modifier ? (this.modifier + ' ') : '';
        s += `public ${modifier}${this.kind.name.toLowerCase()} ${this.simpleName}`;
        if (this.genericTypes.length) {
            s += `<${this.genericTypes.join(', ')}>`;
        }
        if (this.extends.length) {
            s += ` extends ${this.extends.join(', ')}`;
        }
        if (this.implements.length) {
            s += ` implements ${this.implements.join(', ')}`;
        }
        s += ' {\n\n';
        if (this.inner) {
            let innerClassCode = this.inner.toString(true);
            innerClassCode = innerClassCode.trim().replaceAll('\n', '\n    ');
            s += '    ' + innerClassCode + '\n\n';
        }
        for (let i = 0; i < this.properties.length; i++) {
            let property = this.properties[i];
            let p = property.toString().trim();
            // 枚举常量的最后一个以;结尾
            if (property.constant && i === this.properties.length - 1) {
                p = p.substring(0, p.length - 1) + ';';
            }
            s += '    ' + p.replaceAll('\n', '\n    ') + '\n';
            // 枚举常量多一个空白行
            if (property.constant) {
                s += '\n';
            }
        }
        for (let method of this.methods) {
            let methodCode = method.toString();
            methodCode = methodCode.replaceAll('\n', '\n    ');
            s += '\n    ' + methodCode;
        }
        s += '\n}\n';
        s = s.replaceAll('\n\n\n', '\n\n').replaceAll('\n    \n', '\n\n');
        return s;
    }

}
